<?php

namespace App\Http\Services\Api\V1\App\Product;

use App\Http\Requests\Products\ShowProductReviewRequest;
use App\Models\Currency;
use App\Models\Customers\Customer;
use App\Models\Products\Product;
use App\Models\Products\ProductOption;
use App\Models\Products\ProductOptionValue;
use App\Models\Products\ProductSpecial;
use App\Models\Products\Review;
use App\Services\Utils\ApiChecker;
use App\Services\Utils\DeSensitive;
use App\Services\Utils\FormatPrice;
use App\Services\Utils\Guard;
use App\Services\Utils\ImageHelper;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;

class ProductDetailService
{
    const DEFAULT_COUNT = 2;

    use ApiChecker;

    /**
     * @param Currency $currency
     * @param $product_id
     * @return Product
     * @throws \Exception
     */
    public function getProductDetail(Currency $currency, int $product_id)
    {
        /** @var Product $product_detail */
        $product_detail = (new Product)
            ->filterOnShelf()
            ->with('filterProductDescriptionByLanguage',
                'productSpecials',
                'productImages',
                'appPlatformModels',
                'productAttributes.attributeDescription',
                'productAttributes.attribute.attributeGroupDescription.attributeGroup',
                'orderProducts.orderByPaid',
//                'filterReviewsByStatusOn.customer',
//                'filterReviewsByStatusOn.orderOptions',
                'productDiscounts')
            ->select(['product_id', 'image', 'price', 'product_video',
                'points', 'viewed', 'quantity', 'minimum'
            ])
            ->find($product_id);

        $this->checkItemExist($product_detail);

        // 更新商品访问量
        $product_detail->increment('viewed');

        $this->transformProductDetail($product_detail, $currency);

        return $product_detail;
    }

    /**
     * @param Currency $currency
     * @param $product_id
     * @return array
     * @throws \Exception
     */
    public function getProductSpec(Currency $currency, $product_id)
    {
        /** @var Product $product */
        $product = (new Product)
            ->filterOnShelf()
            ->with('productOptions.productOptionValues.optionValue',
                'productOptions.option.optionDescription'
            )
            ->select(['product_id', 'image', 'price'])
            ->find($product_id);

        $this->checkItemExist($product);

        $product_specs = $this->transformProductSpecs($product, $currency);

        return $product_specs;
    }

    /**
     * @param Product $product
     * @param Currency $currency
     * @return array
     */
    public function transformProductSpecs(Product $product, Currency $currency)
    {
//        $origin_price  = $product->filterProductDiscountByLatest->price ?? $product->price;
//        $special_price  = $product->filterProductSpecialByLatest->price ?? ProductSpecial::DEFAULT_PRODUCT_SPECIAL_PRICE;
//
//        $product->price = FormatPrice::formatPrice($special_price ?: $origin_price, $currency);
//        $product->symbol_left = $currency->symbol_left;

        /** @var Collection $product_options */
        $product_options = $product->productOptions;

        $product_options = $this->transformProductOptions($product_options, $currency);

//        $product->addHidden('productOptionValuesByType', 'filterProductSpecialByLatest', 'filterProductDiscountByLatest','productOptions');

        return compact('product_options');
    }

    /**
     * @param ShowProductReviewRequest $request
     * @return LengthAwarePaginator
     * @throws \Exception
     */
    public function getProductReviews(ShowProductReviewRequest $request)
    {
        $product_id = $request->product_id;

        /** @var Product $product_detail */
        $product = (new Product)->filterOnShelf()
            ->find($product_id);

        $this->checkItemExist($product);

        /** @var LengthAwarePaginator $product_reviews */
        $product_reviews = (new Review)->where('product_id', $product->product_id)
            ->where('status', Review::REVIEW_STATUS_ON)
            ->with('customer', 'orderOptions', 'reviewImages')
            ->latest('date_added')
            ->paginate($request->per_page ?: self::DEFAULT_COUNT);

        $this->transformProductReviews($product_reviews);

        return $product_reviews;
    }

    /**
     * @param Collection $product_attributes
     * @return Collection|\Illuminate\Support\Collection
     */
    private function transformProductAttributes(Collection $product_attributes)
    {
        $product_attribute_values = $product_attributes->sortBy('attribute.attributeGroupDescription.attributeGroup.sort_order')
            ->groupBy('attribute.attribute_group_id')
            ->values();

        $product_attribute_values = $product_attribute_values->map(function (Collection $product_attribute_value) {

            $product_attribute['attribute_group_id'] = $product_attribute_value->first()->attribute->attribute_group_id ?? null;
            $product_attribute['attribute_group_name'] = $product_attribute_value->first()->attribute->attributeGroupDescription->name ?? null;
            $product_attribute['attribute_group_sort_order'] = $product_attribute_value->first()->attribute->attributeGroupDescription->attributeGroup->sort_order ?? null;

            $product_attribute['attribute_values'] = $product_attribute_value->map(function ($product_attribute) {
                return [
                    'product_id'     => $product_attribute->product_id,
                    'product_text'   => $product_attribute->text,
                    'attribute_id'   => $product_attribute->attribute_id,
                    'attribute_name' => $product_attribute->attributeDescription->name ?? null,
                ];
            });

            return $product_attribute;
        });

        return $product_attribute_values ;
    }

    /**
     * @param Product $product_detail
     * @param $currency
     */
    private function transformProductDetail(Product $product_detail, Currency $currency)
    {
        // 当折扣价，起购数量为1时，折扣价等于原价。
        $origin_price = Product::getProductOriginPrice($product_detail);
        $special_price = $product_detail->productSpecials->first()->price ?? null;

        $customer = Guard::customer();

        $product_detail->name = $product_detail->filterProductDescriptionByLanguage->name ?? null;
        $product_detail->is_wish_product = $customer ? $customer->isProductInWishList($product_detail) : false;
        $product_detail->currency_symbol_left = $currency->symbol_left;
        $product_detail->currency_symbol_right = $currency->symbol_right;
        $product_detail->currency_settle_price = $currency->exchangePrice($product_detail->settle_price); // 这里的商品price不能被处理
        $product_detail->origin_price = $origin_price;
        $product_detail->price = $currency->exchangePrice($product_detail->price);
        $product_detail->special_price = $special_price ? $currency->exchangePrice($special_price) : null;
        $product_detail->sales_volume = Product::getProductSalesVolume($product_detail);
        $product_detail->product_attribute_values = $this->transformProductAttributes($product_detail->productAttributes);

        // 有特价时不计算批量价格，直接不返回
        $product_detail->discounts = $special_price ? [] : $product_detail->productDiscounts;

        $product_detail->addHidden([
            'productSpecials', 'filterReviewsByStatusOn',
            'productAttributes', 'productDiscounts', 'orderProducts'
        ]);
    }

    /**
     * @param LengthAwarePaginator $reviews
     *
     * @return Collection|array|LengthAwarePaginator
     */
    private function transformProductReviews(LengthAwarePaginator $reviews)
    {
        $product_reviews_collection = $reviews->getCollection();

        $product_reviews_collection->transform(function(Review $review){

            $review->customer_image = $review->customer->image ?? null;
            $review->customer_fullname = DeSensitive::asteriskName(
                $review->customer->fullname ?? $review->author, 4);

            $review->addHidden(['customer']);

            return $review;
        });

        return $reviews;
    }

    /**
     * @param Collection $product_options
     * @param Currency $currency
     * @return mixed
     */
    private function transformProductOptions(Collection $product_options, Currency $currency )
    {
        $product_options = $product_options->map(function (ProductOption $product_option) use ($currency) {

            $option_values = $product_option->productOptionValues->map(function (ProductOptionValue $product_option_value) use ($currency) {
                $option_price = $product_option_value->price;
                $image = $product_option_value->image ?: $product_option_value->optionValue->image ?? null;
                return [
                    'product_id'                    => $product_option_value->product_id,
                    "quantity"                      => $product_option_value->quantity,
                    "subtract"                      => $product_option_value->subtract,
                    "image"                         => ImageHelper::generateImagePath($image),
                    "option_price"                  => $option_price ? FormatPrice::formatPrice($option_price, $currency) : Product::PRODUCT_PRICE_DEFAULT,
                    "price_prefix"                  => $product_option_value->price_prefix,
                    "points"                        => $product_option_value->points,
                    "points_prefix"                 => $product_option_value->points_prefix,
                    'product_option_value_id'       => $product_option_value->product_option_value_id,
                    'option_value_description_name' => $product_option_value->optionValueDescription->name ?? null,
                ];
            });

            return [
                'option_description_name' => $product_option->option->optionDescription->name,
                'product_option_id'       => $product_option->product_option_id,
                'required'                => $product_option->required,
                'option_type'             => $product_option->option->type,
                // 没有对应的option_values，显示 option 本身的 value 值
                'option_values'           => count($option_values) ? $option_values : $this->assembleProductOptionValue($product_option),
            ];
        });
        return $product_options;
    }

    /**
     * @param ProductOption $product_option
     * @return array
     */
    private function assembleProductOptionValue(ProductOption $product_option)
    {
        $product_option['product_id'] = $product_option->product_id;
        $product_option['product_option_value_id'] = 0;
        $product_option['option_value_description_name'] = $product_option->value;

        return [$product_option];
    }
}